/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022. All rights reserved.
 *
 * Description: SLE private service register sample of client.
 */
/**
 * Copyright (c) kidwjb
 *
 * Description: sle GATE demo. \n
 *              This file is a sle GATE demo. \n
 *
 * History: \n
 * 2025-04-08, Create file. \n
 */
#include "pinctrl.h"
#include "common_def.h"
#include "soc_osal.h"
#include "osal_wait.h"
#include "app_init.h"
#include "sle_device_discovery.h"
#include "sle_connection_manager.h"
#include "sle_ssap_client.h"
#include "cmsis_os2.h"
#include "MQTTClientPersistence.h"
#include "MQTTClient.h"
#include "wifi_connect.h"
#include "lwip/sntp.h"
#include <sys/time.h>
#include "uart.h"
#include "http.h"
#include "MQTTClientPersistence.h"
#include "MQTTClient.h"

#define SLE_SEEK_INTERVAL_DEFAULT 100
#define SLE_SEEK_WINDOW_DEFAULT 100
#define SLE_MTU_SIZE_DEFAULT 300
#define UUID_16BIT_LEN 2
#define UUID_128BIT_LEN 16
#define MSG_QUEUE_NUMBER 10
#define SLE_CONNNECT_MAX 8
#define DELAY_100MS 100
#define DELAY_200MS 200
#define DELAY_500MS 500
#define DELAY_1MIN 1000 * 30
#define UART_BAUDRATE                       9600
#define UART_DATA_8BITS                     3
#define UART_STOP_BITS                      1
#define UART_PARITY_BIT                     0
#define UART_TRANSFER_SIZE                  256
#define UART_TASK_PRIO                      25
#define UART_TASK_STACK_SIZE                0x1000
#define ASPRO_UART_TXD_PIN                  8
#define ASPRO_UART_RXD_PIN                  7
#define ASPRO_UART_BUS_ID                   2
#define SCREEN_UART_TXD_PIN                 15
#define SCREEN_UART_RXD_PIN                 16
#define SCREEN_UART_BUS_ID                  1
#define DELAY_TIME_MS 500
#define KEEP_ALIVE_INTERVAL 120

enum {
    INDEX0,
    INDEX1,
    INDEX2,
    INDEX3,
    INDEX4,
    INDEX5,
    INDEX6,
    INDEX7,
    INDEX8,
    INDEX9,
    INDEX10,
    INDEX11,
    INDEX12,
    INDEX13,
    INDEX14,
    INDEX15,
};

osThreadId_t mqtt_init_task_id;

#define SERVER_IP_ADDR "47.109.75.129" // 接入地址 hostname
#define SERVER_IP_PORT 1883                              // port 单片机一般使用MQTT，端口1883
#define CLIENT_ID "my_LED_0_0_2025051208"                // client_id

#define MQTT_CMDTOPIC_SUB "sensor/control" // 平台下发命令  订阅主题

#define MQTT_DATATOPIC_PUB "sensor/data"                 // 属性上报topic 发布主题

osMessageQueueId_t MsgQueue_ID; // 消息队列的ID
#define SENDJSON_PACK \
"{\n" \
"  \"temp\": %lu,\n" \
"  \"huimi\": %lu,\n" \
"  \"CO2_Val\": %lu,\n" \
"  \"PH_Val\": %.2f,\n" \
"  \"O2_Val\": %.2f,\n" \
"  \"light_Val\": %.2f,\n" \
"  \"TDS_Val\": %.2f,\n" \
"  \"pest_check\": %lu\n" \
"}"
char g_send_buffer[512] = {0}; // 发布数据缓冲区
char g_response_id[100] = {0}; // 保存命令id缓冲区

typedef struct {
    uint8_t data[100];
    uint8_t connect_id;
} notify_data_t; // �?定义消息

notify_data_t notify_data_put;
notify_data_t notify_data_get;

sle_addr_t g_remote_addr = {0};
sle_announce_seek_callbacks_t sle_announce_seek_callbacks = {0};
sle_connection_callbacks_t sle_connection_callbacks = {0};
ssapc_callbacks_t ssapc_callbacks = {0};
uint16_t g_conn_id[SLE_CONNNECT_MAX] = {0};
uint8_t connect_num;
ssapc_find_service_result_t g_find_service_result = {0};
ssapc_find_property_result_t ssapc_find_property_result = {0};
static sle_addr_t g_sle_uart_remote_addr = {0};

uint8_t remote_addr_key[SLE_CONNNECT_MAX][2] = {0}; // 创建�?值�??

typedef struct sensorData_t{
    uint32_t temp;
    uint32_t huimi;
    uint32_t CO2_Val;
    float PH_Val;
    float O2_Val;
    float light_Val;
    float TDS_Val;
    uint32_t pest_check;

}sensorData;

sensorData getData = {
    .O2_Val = 3.5,
    .huimi = 64.3,
    .temp = 25,
};

uint32_t  sendBuff[18] = {0x000000ff,0/*CO2*/,0/*PH*/,0/*TDS*/,0/*O2*/,0/*temp*/,0/*huimi*/,0/*light*/,0x000000ff,
                          0x000000ff,0/*CO2*/,0/*PH*/,0/*TDS*/,0/*O2*/,0/*temp*/,0/*huimi*/,0/*light*/,0x000000fe};
uint8_t controlBuff[9] = {0xff,0/*灯*/,0/*碱性水泵*/,0/*营养液泵*/,0/*风扇*/,0/*加热器*/,0/*酸性水泵*/,0/*加湿器*/,0xfe};

void *my_memcpy(void * dest, const void * src, size_t num)
{
    uint8_t *ptr_d = (uint8_t *)dest;
    uint8_t *ptr_s = (uint8_t *)src;
    uint8_t i = 0;
    for(i = 0;i < num;i++)
    {
        *(ptr_d + num -1 -i) = *(ptr_s + i);
    }
    return ptr_d;
}

//*******************MQTT**************//

uint8_t g_cmdFlag;
volatile MQTTClient_deliveryToken deliveredToken;
extern int MQTTClient_init(void);

MQTTClient client;


// 处理连接丢失回调函数
void connect_lost(void *context, char *cause)
{
    unused(context);
    osal_printk("connection lost : %s\r\n", cause);
}
//-----------------------------------//

// 接收消息处理//
void parse_after_equal(const char *input, char *output)
{
    const char *equalsign = strchr(input, '=');
    if (equalsign != NULL) {
        // 计算等号后面的字符串长度
        strcpy(output, equalsign + 1);
    }
}

// 处理接收到消息的回调函数
int message_arrive(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    unused(context);
    unused(topicLen);
    osal_printk("[Message receive topic]: %s\r\n", topicName);
    osal_printk("[Message] : %s \r\n", (char *)message->payload);
    // LED 控制
    if (strstr((char *)message->payload, "true") != NULL) {
        osal_printk("\r\n broker message is TRUE !!! \r\n");
    } else {
        osal_printk("\r\n broker message is FAUSE !!! \r\n");
    }
    // 解析命令id
    parse_after_equal(topicName, g_response_id);
    g_cmdFlag = 1;
    memset((char *)message->payload, 0, message->payloadlen);

    return 1; // 表示消息已被处理
}
//----------------------------------------------//

// 处理消息传递完成回调函数
void delivered(void *context, MQTTClient_deliveryToken dt)
{
    unused(context);
    osal_printk("Message with token value %d delivery confirmed\r\n", dt);

    deliveredToken = dt;
}

//------------------------------------------------//

// 订阅主题
int mqtt_subscribe(const char *topic)
{
    osal_printk("subscribe start!\r\n");
    MQTTClient_subscribe(client, topic, 1);
    return 0;
}
//--------------------------------------------//

// 发布主题

int mqtt_publish(const char *topic, char *msg)
{
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;
    int ret = 0;
    pubmsg.payload = msg;
    pubmsg.payloadlen = (int)strlen(msg);
    pubmsg.qos = 1;
    pubmsg.retained = 0;

    osal_printk("[topic]:%s\r\n", topic);
    osal_printk("[msg]:%s\r\n", msg);
    ret = MQTTClient_publishMessage(client, topic, &pubmsg, &token);
    if (ret != MQTTCLIENT_SUCCESS) {
        osal_printk("mqtt publish failed \r\n");
        return ret;
    }
    return ret;
}

//-------------------------------------------//

static errcode_t mqtt_connect(void)
{
    int ret;
    MQTTClient_connectOptions mqtt_connect_opt =
        MQTTClient_connectOptions_initializer; // MQTT 3.1.1 non-WebSockets,适用于嵌入式设备
    // 初始化mqtt客户端
    MQTTClient_init();

    // 创建mqtt客户端
    ret = MQTTClient_create(&client, SERVER_IP_ADDR, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    if (ret != MQTTCLIENT_SUCCESS) {
        osal_printk("Failed to create MQTT client,return code %d\r\n", ret);
        return ERRCODE_FAIL;
    }
    mqtt_connect_opt.keepAliveInterval = KEEP_ALIVE_INTERVAL;
    mqtt_connect_opt.cleansession = 1;


    // 创建回调函数
    MQTTClient_setCallbacks(client, NULL, connect_lost, message_arrive, delivered);

    // 尝试连接
    if ((ret = MQTTClient_connect(client, &mqtt_connect_opt)) != MQTTCLIENT_SUCCESS) {
        osal_printk("[MQTT_Task] : Failed to connect ,return code %d\r\n", ret);
        MQTTClient_destroy(&client); // 连接失败时销毁客户端
        return ERRCODE_FAIL;
    }
    osal_printk("[MQTT_Task] : Connected to MQTT brocker\r\n"); 
    osDelay(DELAY_TIME_MS);

    // 订阅MQTT主题
    mqtt_subscribe(MQTT_CMDTOPIC_SUB);

    while (1) {
        // 属性上报部分
        osDelay(DELAY_TIME_MS);
        snprintf(g_send_buffer,sizeof(g_send_buffer),SENDJSON_PACK,getData.temp,getData.huimi,getData.CO2_Val,
                        getData.PH_Val - 5,getData.O2_Val,getData.light_Val,getData.TDS_Val,getData.pest_check);
        mqtt_publish(MQTT_DATATOPIC_PUB, g_send_buffer);

        osDelay(DELAY_TIME_MS);
    }
    return ERRCODE_SUCC;
}

void mqtt_init_task(void)
{
    osDelay(DELAY_TIME_MS);
    wifi_connect();
    osDelay(DELAY_TIME_MS);
    mqtt_connect();
}

//_______________________________________________________//


//******************uart*********************//
uint8_t aspro_uart_tx_buff[UART_TRANSFER_SIZE];
uint8_t screen_uart_tx_buff[UART_TRANSFER_SIZE];

void aspro_rx_cbk(const void *buffer, uint16_t length, bool error)
{
    unused(error);
    const uint8_t *ptr = buffer;
    uint8_t i = 0;
    ssapc_write_param_t param = {0};
    param.handle =
        2; /*2:
            必须是让句柄等于2才能够发送，这个是property的句柄值，但是这个程序不知为何无法正常接收到property句柄，所以直接赋值2*/
    param.type = SSAP_PROPERTY_TYPE_VALUE;
    osal_printk("[sreen_uart recieve]:");
    for(i = 0;i < length;i++)
    {
        osal_printk("%02x ",*(ptr+ i));
    }
    osal_printk(" recieve len:%d\r\n",length);
    if(ptr[0] == 0xAA && ptr[3] == 0xBB)
    {
        controlBuff[(ptr[1])] = ptr[2];
        param.data_len = sizeof(controlBuff);
        param.data = controlBuff;
        ssapc_write_req(0, remote_addr_key[0][INDEX1], &param); /*0 :client id*/
    }
}

void screen_rx_cbk(const void *buffer, uint16_t length, bool error)
{
    unused(error);
    uint8_t i = 0;
    const uint8_t *ptr = buffer;
    ssapc_write_param_t param = {0};
    param.handle =
        2; /*2:
            必须是让句柄等于2才能够发送，这个是property的句柄值，但是这个程序不知为何无法正常接收到property句柄，所以直接赋值2*/
    param.type = SSAP_PROPERTY_TYPE_VALUE;


    osal_printk("[sreen_uart recieve]:");
    for(i = 0;i < length;i++)
    {
        osal_printk("%02x ",*(ptr+ i));
    }
    osal_printk(" recieve len:%d\r\n",length);
    if(ptr[0] == 0xAA)
    {
        if(ptr[1] == 0x11)//温度
        {
            sendBuff[14] = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2];
            sendBuff[5]  = (ptr[10] << 24) | (ptr[9] << 16) | (ptr[8] << 8) | ptr[7];
        }
        else if(ptr[1] == 0x22)//湿度
        {
            sendBuff[15] = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2];
            sendBuff[6]  = (ptr[10] << 24) | (ptr[9] << 16) | (ptr[8] << 8) | ptr[7];
        }
        else if(ptr[1] == 0x33)//CO2
        {
            sendBuff[10] = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2];
            sendBuff[1]  = (ptr[10] << 24) | (ptr[9] << 16) | (ptr[8] << 8) | ptr[7];
        }
        else if(ptr[1] == 0x44)//PH
        {
            float high = ptr[2] * 10 + ptr[6];
            high = high / 10;
            memcpy(&(sendBuff[11]),&high,sizeof(float));

            float low = ptr[7] * 10 + ptr[11];
            low = low / 10;
            memcpy(&(sendBuff[2]),&low,sizeof(float));
        }
        else if(ptr[1] == 0x55)//O2
        {
            float high = ptr[2] * 10 + ptr[6];
            high = high / 10;
            memcpy(&(sendBuff[13]),&high,sizeof(float));

            float low = ptr[7] * 10 + ptr[11];
            low = low / 10;
            memcpy(&(sendBuff[4]),&low,sizeof(float));
        }
        else if(ptr[1] == 0x66)//光强
        {
            float high = ptr[2] * 10 + ptr[6];
            high = high / 10;
            memcpy(&(sendBuff[16]),&high,sizeof(float));

            float low = ptr[7] * 10 + ptr[11];
            low = low / 10;
            memcpy(&(sendBuff[7]),&low,sizeof(float));
        }

        else if(ptr[1] == 0x77)//tds
        {
            float high = ptr[2] * 10 + ptr[6];
            high = high / 10;
            memcpy(&(sendBuff[12]),&high,sizeof(float));

            float low = ptr[7] * 10 + ptr[11];
            low = low / 10;
            memcpy(&(sendBuff[3]),&low,sizeof(float));
        }

        param.data_len = sizeof(sendBuff);
        param.data = (uint8_t *)sendBuff;
        ssapc_write_req(0, remote_addr_key[0][INDEX1], &param); /*0 :client id*/
    }
    else if(ptr[0] == 0xBB)
    {
        controlBuff[(ptr[1] >> 4)] = ptr[2];
        param.data_len = sizeof(controlBuff);
        param.data = controlBuff;
        ssapc_write_req(0, remote_addr_key[0][INDEX1], &param); /*0 :client id*/
    }
}

static void My_uart_pin_init(void)
{
    uapi_pin_set_mode(ASPRO_UART_TXD_PIN,PIN_MODE_2);//引脚模式设置�?2
    uapi_pin_set_mode(ASPRO_UART_RXD_PIN,PIN_MODE_2);
    uapi_pin_set_mode(SCREEN_UART_TXD_PIN,PIN_MODE_1);//引脚模式设置�?1
    uapi_pin_set_mode(SCREEN_UART_RXD_PIN,PIN_MODE_1);
}

static uart_buffer_config_t aspro_uart_buffer_config = {
    .rx_buffer = aspro_uart_tx_buff,
    .rx_buffer_size = UART_TRANSFER_SIZE
};

static uart_buffer_config_t screen_uart_buffer_config = {
    .rx_buffer = screen_uart_tx_buff,
    .rx_buffer_size = UART_TRANSFER_SIZE
};

static void uart_config(void)
{
    errcode_t ret;
    uart_attr_t attr = {
        .baud_rate = UART_BAUDRATE,
        .data_bits = UART_DATA_8BITS,
        .stop_bits = UART_STOP_BITS,
        .parity = UART_PARITY_BIT
    };
    //ASPRO串口配置初�?�化
    uart_pin_config_t aspro_pin_config = {
        .tx_pin = ASPRO_UART_TXD_PIN,
        .rx_pin = ASPRO_UART_RXD_PIN,
        .cts_pin = PIN_NONE,
        .rts_pin = PIN_NONE
    };
    uapi_uart_deinit(ASPRO_UART_BUS_ID); 
    uapi_uart_init(ASPRO_UART_BUS_ID, &aspro_pin_config, &attr, NULL, &aspro_uart_buffer_config);
    uapi_uart_unregister_rx_callback(ASPRO_UART_BUS_ID);
    ret = uapi_uart_register_rx_callback(ASPRO_UART_BUS_ID,
                                                   UART_RX_CONDITION_FULL_OR_IDLE,
                                                   1, aspro_rx_cbk);
    if(ret == ERRCODE_FAIL)
    {
        osal_printk("aspro cbk register fail\r\n");
    }
    
    //串口屏配置初�?�化
    uart_pin_config_t screen_pin_config = {
        .tx_pin = SCREEN_UART_TXD_PIN,
        .rx_pin = SCREEN_UART_RXD_PIN,
        .cts_pin = PIN_NONE,
        .rts_pin = PIN_NONE
    };
    uapi_uart_deinit(SCREEN_UART_BUS_ID); 
    uapi_uart_init(SCREEN_UART_BUS_ID, &screen_pin_config, &attr, NULL, &screen_uart_buffer_config);
    uapi_uart_unregister_rx_callback(SCREEN_UART_BUS_ID);
    ret = uapi_uart_register_rx_callback(SCREEN_UART_BUS_ID,
                                                   UART_RX_CONDITION_FULL_OR_IDLE,
                                                   1, screen_rx_cbk);
    if(ret == ERRCODE_FAIL)
    {
        osal_printk("screen cbk register fail\r\n");
    }
}

static void *uart_task(const char *arg)
{
    unused(arg);
    uint8_t Buff[256] = {0};
    My_uart_pin_init();
    uart_config();
    while(1)
    {
        /**/
        snprintf((char *)Buff, sizeof(Buff),"overview.temp.txt=\"%d\"\xff\xff\xff",getData.temp);
        data_send(Buff,strlen((char *)Buff));
        memset(Buff,0,sizeof(Buff));

        snprintf((char *)Buff, sizeof(Buff),"overview.huimi.txt=\"%d\"\xff\xff\xff",getData.huimi);
        data_send(Buff,strlen((char *)Buff));
        memset(Buff,0,sizeof(Buff));

        snprintf((char *)Buff, sizeof(Buff),"overview.CO2.txt=\"%d\"\xff\xff\xff",getData.CO2_Val);
        data_send(Buff,strlen((char *)Buff));
        memset(Buff,0,sizeof(Buff));

        snprintf((char *)Buff, sizeof(Buff),"overview.PH.txt=\"%.2f\"\xff\xff\xff",getData.PH_Val - 5);
        data_send(Buff,strlen((char *)Buff));
        memset(Buff,0,sizeof(Buff));

        snprintf((char *)Buff, sizeof(Buff),"overview.O2.txt=\"%.2f\"\xff\xff\xff",getData.O2_Val);
        data_send(Buff,strlen((char *)Buff));
        memset(Buff,0,sizeof(Buff));

        snprintf((char *)Buff, sizeof(Buff),"overview.light.txt=\"%.2f\"\xff\xff\xff",getData.light_Val);
        data_send(Buff,strlen((char *)Buff));
        memset(Buff,0,sizeof(Buff));
        
        snprintf((char *)Buff, sizeof(Buff),"overview.tds.txt=\"%.2f\"\xff\xff\xff",getData.TDS_Val);
        data_send(Buff,strlen((char *)Buff));
        memset(Buff,0,sizeof(Buff));

        osal_msleep(2000);
    }
    
    return NULL;
}
//----------------uart------------------------//

//***************queue*******************//

void queue_notification_deal_task(void)
{
    osStatus_t status = 0;
    uint8_t i = 0;
    while (1) {
        status = osMessageQueueGet(MsgQueue_ID, &notify_data_get, 0, 0);
        if (status == osOK) {
            osal_printk("con_id:%d queue deal :\r\n %02x\r\n", notify_data_get.connect_id, notify_data_get.data[INDEX1]);
            for(i = 0;i < 30;i++)
            {
                osal_printk("%02x ",notify_data_get.data[i]);
            }
            osal_printk("\r\n");

            if(notify_data_get.data[INDEX0] == 0xFF && notify_data_get.data[29] == 0xFE)
            {
                my_memcpy(&(getData.CO2_Val),&(notify_data_get.data[1]),sizeof(getData.CO2_Val));

                memcpy(&(getData.PH_Val),&(notify_data_get.data[5]),sizeof(getData.PH_Val));

                memcpy(&(getData.TDS_Val),&(notify_data_get.data[9]),sizeof(getData.TDS_Val));

                memcpy(&(getData.light_Val),&(notify_data_get.data[25]),sizeof(getData.light_Val));

            }
        }
        osal_msleep(DELAY_500MS); // �?500ms处理一次队列中的数�?
    }
    memset(&notify_data_get,0,sizeof(notify_data_get));
}

//---------------queue-------------------//

//**************notification*************//

void sle_notification_cbk(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data, errcode_t status)
{
    unused(client_id);
    unused(status);
    notify_data_put.connect_id = conn_id;
    memcpy_s(notify_data_put.data, sizeof(notify_data_put.data), data->data, data->data_len);
    osMessageQueuePut(MsgQueue_ID, &notify_data_put, 0, 0); // 将数�?入队
    memset(&notify_data_put,0,sizeof(notify_data_put));
}
//----------------notification--------------//

//***************seek******************//
void sle_scan_start(void)
{
    sle_seek_param_t sle_seek_param = {0};
    sle_seek_param.own_addr_type = 0;     // �?�?地址类型
    sle_seek_param.filter_duplicates = 0; // 重�?�过滤开关，0：关�?�?1：开�?
    sle_seek_param.seek_filter_policy = SLE_SEEK_FILTER_ALLOW_ALL;
    sle_seek_param.seek_phys = SLE_SEEK_PHY_1M;
    sle_seek_param.seek_type[0] = SLE_SEEK_PASSIVE;
    sle_seek_param.seek_interval[0] = SLE_SEEK_INTERVAL_DEFAULT;
    sle_seek_param.seek_window[0] = SLE_SEEK_WINDOW_DEFAULT;
    sle_set_seek_param(&sle_seek_param);
    sle_start_seek();
}
void sle_enable_cbk(errcode_t status)
{
    if (status == 0) {
        osal_printk("sle enable: %d.\r\n", status);
        sle_scan_start();
    }
}
void sle_sample_seek_enable_cbk(errcode_t status)
{
    if (status == 0) {
        return;
    }
}
void sle_sample_seek_disable_cbk(errcode_t status)
{
    if (status == 0) {
        sle_connect_remote_device(&g_remote_addr);
    }
}
void sle_sample_seek_result_info_cbk(sle_seek_result_info_t *seek_result_data)
{
    if (seek_result_data != NULL) {
            (void)memcpy_s(&g_remote_addr, sizeof(sle_addr_t), &seek_result_data->addr, sizeof(sle_addr_t));
            sle_stop_seek();
            memcpy_s(&g_sle_uart_remote_addr, sizeof(sle_addr_t), &seek_result_data->addr, sizeof(sle_addr_t));
            remote_addr_key[connect_num][INDEX0] = (uint8_t)seek_result_data->addr.addr[INDEX5];
    }
    
}

void sle_seek_cbk_config(void)
{
    sle_announce_seek_callbacks.sle_enable_cb = sle_enable_cbk;
    sle_announce_seek_callbacks.seek_enable_cb = sle_sample_seek_enable_cbk;
    sle_announce_seek_callbacks.seek_disable_cb = sle_sample_seek_disable_cbk;
    sle_announce_seek_callbacks.seek_result_cb = sle_sample_seek_result_info_cbk;
}
//-------------------seek----------------//

//*******************connect********************//
void connect_state_changed_cbk(uint16_t conn_id,
                               const sle_addr_t *addr,
                               sle_acb_state_t conn_state,
                               sle_pair_state_t pair_state,
                               sle_disc_reason_t disc_reason)
{
    osal_printk("[ssap client] conn state changed conn_id:%d, addr:%02x***%02x%02x\n", conn_id, addr->addr[INDEX0],
                addr->addr[INDEX4], addr->addr[INDEX5]); /* 0 4 5: addr index */
    if (conn_state == SLE_ACB_STATE_CONNECTED) {
        if (pair_state == SLE_PAIR_NONE) {
            sle_pair_remote_device(&g_remote_addr);
        }
        osal_printk("\r\n**** sle server addr:");
        uint8_t i = 0;
        for (i = 0; i < INDEX6; i++) {
            osal_printk("%02x", g_sle_uart_remote_addr.addr[i]);
        }
        osal_printk("\r\n");
        g_conn_id[connect_num] = conn_id;
        remote_addr_key[connect_num][INDEX1] = conn_id;
        connect_num++;
    } else if (conn_state == SLE_ACB_STATE_DISCONNECTED) {
        connect_num--;
        sle_remove_paired_remote_device(addr);
        sle_scan_start();
        osal_printk("sle disconnected,disreason : %d\r\n", disc_reason);
    }
    sle_start_seek();
}
void pair_complete_cbk(uint16_t conn_id, const sle_addr_t *addr, errcode_t status)
{
    osal_printk("[ssap client] pair complete conn_id:%d, addr:%02x***%02x%02x\n", conn_id, addr->addr[INDEX0],
                addr->addr[INDEX4], addr->addr[INDEX5]); /* 0 4 5: addr index */
    if (status == 0) {
        ssap_exchange_info_t info = {0};
        info.mtu_size = SLE_MTU_SIZE_DEFAULT;
        info.version = 1;
        ssapc_exchange_info_req(1, g_conn_id[connect_num], &info);
    }
}
void sle_connection_cbk_config(void)
{
    sle_connection_callbacks.connect_state_changed_cb = connect_state_changed_cbk; // 连接状�?
    sle_connection_callbacks.pair_complete_cb = pair_complete_cbk;
}

//----------------------------connect-------------------------//

//*************************ssap****************************//
void exchange_info_cbk(uint8_t client_id, uint16_t conn_id, ssap_exchange_info_t *param, errcode_t status)
{
    osal_printk("[ssap client] pair complete client id:%d status:%d\n", client_id, status);
    osal_printk("[ssap client] exchange mtu, mtu size: %d, version: %d.\n", param->mtu_size, param->version);
    ssapc_find_structure_param_t find_param = {0};
    find_param.type = SSAP_FIND_TYPE_PRIMARY_SERVICE;
    find_param.start_hdl = 1;
    find_param.end_hdl = 0xFFFF;
    ssapc_find_structure(0, conn_id, &find_param);
}
void sle_sample_find_structure_cbk(uint8_t client_id,
                                   uint16_t conn_id,
                                   ssapc_find_service_result_t *service,
                                   errcode_t status)
{
    osal_printk("[ssap client] find structure cbk client: %d conn_id:%d status: %d \n", client_id, conn_id, status);
    osal_printk("[ssap client] find structure start_hdl:[0x%02x], end_hdl:[0x%02x], uuid len:%d\r\n",
                service->start_hdl, service->end_hdl, service->uuid.len);
    if (service->uuid.len == UUID_16BIT_LEN) {
        osal_printk("[ssap client] structure uuid:[0x%02x][0x%02x]\r\n", service->uuid.uuid[INDEX14],
                    service->uuid.uuid[INDEX15]); /* 14 15: uuid index */
    } else {
        for (uint8_t idx = 0; idx < UUID_128BIT_LEN; idx++) {
            osal_printk("[ssap client] structure uuid[%d]:[0x%02x]\r\n", idx, service->uuid.uuid[idx]);
        }
    }
    g_find_service_result.start_hdl = service->start_hdl;
    g_find_service_result.end_hdl = service->end_hdl;
    memcpy_s(&g_find_service_result.uuid, sizeof(sle_uuid_t), &service->uuid, sizeof(sle_uuid_t));
}
void sle_sample_find_property_cbk(uint8_t client_id,
                                  uint16_t conn_id,
                                  ssapc_find_property_result_t *property,
                                  errcode_t status)
{
    ssapc_find_property_result.handle = property->handle;
    osal_printk(
        "[ssap client] find property cbk, client id: %d, conn id: %d, operate indication: %d, "
        "descriptors count: %d status:%d.\n",
        client_id, conn_id, property->operate_indication, property->descriptors_count, status);
    for (uint16_t idx = 0; idx < property->descriptors_count; idx++) {
        osal_printk("[ssap client] find property cbk, descriptors type [%d]: 0x%02x.\n", idx,
                    property->descriptors_type[idx]);
    }
    if (property->uuid.len == UUID_16BIT_LEN) {
        osal_printk("[ssap client] find property cbk, uuid: %02x %02x.\n", property->uuid.uuid[INDEX14],
                    property->uuid.uuid[INDEX15]); /* 14 15: uuid index */
    } else if (property->uuid.len == UUID_128BIT_LEN) {
        for (uint16_t idx = 0; idx < UUID_128BIT_LEN; idx++) {
            osal_printk("[ssap client] find property cbk, uuid [%d]: %02x.\n", idx, property->uuid.uuid[idx]);
        }
    }
}

void find_structure_cmp_cbk(uint8_t client_id,
                            uint16_t conn_id,
                            ssapc_find_structure_result_t *structure_result,
                            errcode_t status)
{
    unused(conn_id);
    osal_printk("[ssap client] find structure cmp cbk client id:%d status:%d type:%d uuid len:%d \r\n", client_id,
                status, structure_result->type, structure_result->uuid.len);
    if (structure_result->uuid.len == UUID_16BIT_LEN) {
        osal_printk("[ssap client] find structure cmp cbk structure uuid:[0x%02x][0x%02x]\r\n",
                    structure_result->uuid.uuid[INDEX14], structure_result->uuid.uuid[INDEX15]); /* 14 15: uuid index */
    } else {
        for (uint8_t idx = 0; idx < UUID_128BIT_LEN; idx++) {
            osal_printk("[ssap client] find structure cmp cbk structure uuid[%d]:[0x%02x]\r\n", idx,
                        structure_result->uuid.uuid[idx]);
        }
    }
}
void sle_sample_write_cfm_cbk(uint8_t client_id, uint16_t conn_id, ssapc_write_result_t *write_result, errcode_t status)
{
    osal_printk("[ssap client] write cfm cbk, client id: %d status:%d.\n", client_id, status);
    ssapc_read_req(0, conn_id, write_result->handle, write_result->type);
}
void sle_sample_read_cfm_cbk(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *read_data, errcode_t status)
{
    osal_printk("[ssap client] read cfm cbk client id: %d conn id: %d status: %d\n", client_id, conn_id, status);
    osal_printk("[ssap client] read cfm cbk handle: %d, type: %d , len: %d\n", read_data->handle, read_data->type,
                read_data->data_len);
    for (uint16_t idx = 0; idx < read_data->data_len; idx++) {
        osal_printk("[ssap client] read cfm cbk[%d] 0x%02x\r\n", idx, read_data->data[idx]);
    }
}
void ssap_cbk_config(void)
{
    ssapc_callbacks.exchange_info_cb = exchange_info_cbk;
    ssapc_callbacks.find_structure_cb = sle_sample_find_structure_cbk;
    ssapc_callbacks.ssapc_find_property_cbk = sle_sample_find_property_cbk;
    ssapc_callbacks.find_structure_cmp_cb = find_structure_cmp_cbk;
    ssapc_callbacks.notification_cb = sle_notification_cbk;
}
//-------------------------ssap----------------------------//
void *sle_init(void)
{
    sle_seek_cbk_config();
    sle_announce_seek_register_callbacks(&sle_announce_seek_callbacks);
    sle_connection_cbk_config();
    sle_connection_register_callbacks(&sle_connection_callbacks);
    ssap_cbk_config();
    ssapc_register_callbacks(&ssapc_callbacks);
    enable_sle();
    mqtt_init_task();
    return NULL;
}

#define SLE_UUID_CLIENT_TASK_PRIO 24
#define SLE_UUID_CLIENT_STACK_SIZE 0x2000
#define MSGQUEUE_TASK_PRIO 27
#define MSGQUEUE_TASK_STACK_SIZE 0x1000

static void sle_uuid_client_entry(void)
{
    // 创建消息队列
    MsgQueue_ID = osMessageQueueNew(MSG_QUEUE_NUMBER, sizeof(notify_data_t),
                                    NULL); // 消息队列�?的消�?�?数，消息队列�?的消�?大小，属�?
    if (MsgQueue_ID != NULL) {
        osal_printk("ID = %d, Create MsgQueue_ID is OK!\n", MsgQueue_ID);
    }
    osal_task *task_handle = NULL;
    osal_kthread_lock();
    task_handle = osal_kthread_create((osal_kthread_handler)sle_init, 0, "sle_gatt_client", SLE_UUID_CLIENT_STACK_SIZE);
    if (task_handle != NULL) {
        osal_kthread_set_priority(task_handle, SLE_UUID_CLIENT_TASK_PRIO);
        osal_kfree(task_handle);
    }
    task_handle = osal_kthread_create((osal_kthread_handler)uart_task, 0, "uart Task", UART_TASK_STACK_SIZE);
    if (task_handle != NULL) {
        osal_kthread_set_priority(task_handle, UART_TASK_PRIO);
        osal_kfree(task_handle);
    }
    task_handle = osal_kthread_create((osal_kthread_handler)queue_notification_deal_task, 0, "queue_deal",
                                      MSGQUEUE_TASK_STACK_SIZE);
    if (task_handle != NULL) {
        osal_kthread_set_priority(task_handle, MSGQUEUE_TASK_PRIO);
        osal_kfree(task_handle);
    }

    osal_kthread_unlock();
}
/* Run the app entry. */
app_run(sle_uuid_client_entry);
